<?php
/**
 *
 * @author Mr.UBKey
 * @package XPHP
 * @version 0.1 B
 * @copyright XWEB
 */
require_once 'XPHP/DB/Table/Model.php';
class XPHP_Model extends XPHP_DB_Table_Model
{
	/**
	 * Mảng lưu trữ các thông báo lỗi
	 * @var array
	 */
	protected $_errorMessage = array();
	
	public function __construct($id=NULL)
	{
		$this->_name = XPHP_Attribute::ClassAttributes(get_class($this))->__get("table");
		$this->_primaryKey = XPHP_Attribute::ClassAttributes(get_class($this))->__get("primaryKey");
		//Gọi phương thức khởi tạo của lớp cha
		parent::__construct();
		//Gọi tới function __init nếu có sau khi khởi tạo lớp
		if(method_exists(get_class($this), '_init'))
			$this->_init();
		/**
		 * Nếu có truyền vào ID lấy thông tin tương ứng với Id từ database 
		 * lưu vào thuộc tính đối tượng
		 */
		if($id !== NULL)
		{
			//Lấy dữ liệu từ database
			$row = $this->select("$this->_primaryKey = '" . $id . "'");
			//Gán giá trị vào các thuộc tính
			$ref_model = new XPHP_Reflection("XPHP_Model");
			$properties_model = array();
			foreach ($ref_model->getProperties() as $property)
			{
				$properties_model[] = $property->getName();
			}
			//Lấy danh sách các property của lớp thừa kế XPHP_Model
			$ref = new XPHP_Reflection($this);
			foreach ($ref->getProperties() as $property)
			{
				$property_name = $property->getName();
				if(!in_array($property_name, $properties_model))
				{	
					if(isset($row[$property_name]))
						$this->$property_name = $row[$property_name];
				}
			}
		}	
	}
	
	public function getErrorMessage()
	{
		return $this->_errorMessage;
	}

	public function setErrorMessage($error, $message, $field=NULL)
	{
		if($field === NULL)
			$field = "_CUSTOMERROR";
			
		if(isset($this->_errorMessage[$field]) && is_array($this->_errorMessage[$field]))
		{
			$this->_errorMessage[$field] = array_merge(array($error => $message), $this->_errorMessage[$field]);
		}
		else
		{
			$this->_errorMessage[$field] = array($error => $message);
		}
	}
	
	public function isValid()
	{
		$validFlag = true;
		require_once 'XPHP/Reflection.php';
		require_once 'XPHP/Model.php';
		require_once 'XPHP/Model/Validation.php';
		
		//Lấy toàn bộ danh sách các thuộc tính của Model
		$ref_model = new XPHP_Reflection("XPHP_Model");
		$properties_model = array();
		foreach ($ref_model->getProperties() as $property)
		{
			$properties_model[] = $property->getName();
		}
		//Lấy danh sách các property của lớp thừa kế XPHP_Model
		$ref = new XPHP_Reflection($this);
		foreach ($ref->getProperties() as $property)
		{
			$property_name = $property->getName();
			if(!in_array($property_name, $properties_model))
			{	
				$validation = new XPHP_Model_Validation();
				$property_attribute = XPHP_Attribute::PropertyAttributes($this, $property_name)->attributes;
				//Nếu có attribute validation
				if(isset($property_attribute["validate"]))
				{
					$property_validate = $property_attribute["validate"]->attributes;
					foreach ($property_validate as $valid => $value)
					{
						if(!$validation->$valid($value, $this->$property_name))
							$validFlag = false;
					}
					$this->_errorMessage[$property_name] = $validation->errorMessage;
				}
			}
		}
		
		return $validFlag;
	}
	
	public function insert($values=NULL, $replace=NULL, $info=NULL)
	{
		//Kiểm tra read_only của model
		$classAttributes = XPHP_Attribute::ClassAttributes($this)->attributes;
		if(isset($classAttributes["read_only"]) && $classAttributes["read_only"] == "true")
		{
			return false;
			throw new XPHP_Exception(get_class($this) . " chỉ được phép đọc .");
		}
		//Nếu truyền vào giá trị insert bình thường
		if($values !== NULL)
			return parent::insert($values, $replace, $info);
		else
		{
			$arrData = array(); //Mảng chứa dữ liệu đưa vào insert
			require_once 'XPHP/Reflection.php';
			require_once 'XPHP/Model.php';
			require_once 'XPHP/Model/Validation.php';
		
			//Lấy toàn bộ danh sách các thuộc tính của Model
			$ref_model = new XPHP_Reflection("XPHP_Model");
			$properties_model = array();
			foreach ($ref_model->getProperties() as $property)
			{
				$properties_model[] = $property->getName();
			}
			//Lấy danh sách các property của lớp thừa kế XPHP_Model
			$ref = new XPHP_Reflection($this);
			foreach ($ref->getProperties() as $property)
			{
				$property_name = $property->getName();
				if(!in_array($property_name, $properties_model))
				{
					//Đánh dấu thuộc tính được insert hay không ? Mặc định là có
					$insert = true;
					$property_attribute = XPHP_Attribute::PropertyAttributes($this, $property_name)->attributes;
					//Nếu có attribute command
					if(isset($property_attribute["command"]))
					{
						$property_command = $property_attribute["command"]->attributes;
						foreach ($property_command as $command => $value)
						{
							if($command == "insert" && $value == "false")
								$insert = false;
						}
					}
					if($insert)
						//Lấy tên thuộc tính trong lớp và giá trị của nó đưa vào mảng
   						$arrData[$property_name] = $this->$property_name;
				}
			}
			try {
				return parent::insert($arrData);
			}catch (XPHP_Exception $ex){
				throw new XPHP_Exception("Không thể insert model vào bảng.");
			}
		}
	}
	
	public function update($values=NULL, $condition=NULL, $info=NULL)
	{
		//Kiểm tra read_only của model
		$classAttributes = XPHP_Attribute::ClassAttributes($this)->attributes;
		if(isset($classAttributes["read_only"]) && $classAttributes["read_only"] == "true")
		{
			return false;
			throw new XPHP_Exception(get_class($this) . " chỉ được phép đọc .");
		}
		if($values !== NULL && $condition !== NULL)
			return parent::update($values, $condition, $info);
		else 
		{
			$arrData = array(); //Mảng chứa dữ liệu đưa vào update
			require_once 'XPHP/Reflection.php';
			require_once 'XPHP/Model.php';
			require_once 'XPHP/Model/Validation.php';
		
			//Lấy toàn bộ danh sách các thuộc tính của Model
			$ref_model = new XPHP_Reflection("XPHP_Model");
			$properties_model = array();
			foreach ($ref_model->getProperties() as $property)
			{
				$properties_model[] = $property->getName();
			}
			//Lấy danh sách các property của lớp thừa kế XPHP_Model
			$ref = new XPHP_Reflection($this);
			foreach ($ref->getProperties() as $property)
			{
				$property_name = $property->getName();
				if(!in_array($property_name, $properties_model))
				{
					//Đánh dấu thuộc tính được update hay không ? Mặc định là có
					$update = true;
					$property_attribute = XPHP_Attribute::PropertyAttributes($this, $property_name)->attributes;
					//Nếu có attribute command
					if(isset($property_attribute["command"]))
					{
						$property_command = $property_attribute["command"]->attributes;
						foreach ($property_command as $command => $value)
						{
							if($command == "update" && $value == "false")
								$update = false;
						}
					}
					if($update)
						//Lấy tên thuộc tính trong lớp và giá trị của nó đưa vào mảng
   						$arrData[$property_name] = $this->$property_name;
				}
			}
			try {
				$key = $this->_primaryKey;
				return parent::update($arrData, "`$key` = '" . $this->$key . "'");
			}catch (XPHP_Exception $ex){
				throw new XPHP_Exception("Không thể update model vào bảng.");
			}
		}
	}
	
	public function delete($condition=NULL, $info=NULL)
	{
		//Kiểm tra read_only của model
		$classAttributes = XPHP_Attribute::ClassAttributes($this)->attributes;
		if(isset($classAttributes["read_only"]) && $classAttributes["read_only"] == "true")
		{
			return false;
			throw new XPHP_Exception(get_class($this) . " chỉ được phép đọc .");
		}
		if($condition !== NULL)
			parent::delete($condition);
		else
		{
			try {
				$key = $this->_primaryKey;
				return parent::delete("`$key` = '" . $this->$key . "'");
			}catch (XPHP_Exception $ex){
				throw new XPHP_Exception("Không thể delete model trong bảng.");
			}
		}
	}
	
}